<template>
	<view class="vi_switch">
		<vi-style-controller @click="onChange"
			compName="switch"
			hoverClass="none"
			:control="['background','border']"
			:size="setting.size"
			:type="setting.type"
			:color="color"
			:radius="setting.radius"
			:width="W"
			:height="height"
			:borderWidth="setting.borderWidth"
			:disabled="disabled"
			:readOnly="readOnly"
			:active="inChecked"
			inline
			borderBox
			basicBorder
			basicBackground="#fafafa">
			<view class="vi_switch_box" :style="{
					'width':`calc(100% + ${borW} *2)`,
					'height':`calc(100% + ${borW} *2)`
				}">
				<view class="vi_switch_block" :class="'vi_shadow_'+setting.size" :style="{
						'left': distance,
						'top':0
					}">
					<vi-style-controller
						compName="switchBlock"
						:size="setting.size"
						:type="setting.type"
						:color="color"
						:radius="setting.radius"
						:width="height"
						:height="height"
						:borderWidth="setting.borderWidth"
						:disabled="disabled"
						:readOnly="readOnly"
						:active="inChecked"
						plain
						borderBox
						basicText
						basicBorder
						basicBackground="#fff">
						<slot>
							<view :class="buttonClass||''">
								<text class="iconfont" :class="buttonIcon" v-if="buttonIcon"></text>
								<text v-else-if="buttonText">{{buttonText}}</text>
							</view>
						</slot>
					</vi-style-controller>
				</view>
			</view>
		</vi-style-controller>
	</view>
</template>

<script>
	export default {
		name:"viSwitch",
		options:{//样式穿透，微信须设置
			styleIsolation: "shared"
		},
		model:{
			prop:"value",
			event:"input"
		},
		props:{
			checked:{
				type:[Boolean,null],
				default:false
			},
			type:{
				type:[String,null],
				default:null
			},
			color:{
				type:[String,null],
				default:""
			},
			//value为绑定值模式，启用后onValue必须设置，返回对应状态值，使用严格比较
			mode:{
				type:[String,null],
				default:""
			},
			value:{
				type:[Boolean,String,Number,null],
				default:null
			},
			onValue:{
				type:[Boolean,String,Number,null],
				default:null
			},
			offValue:{
				type:[Boolean,String,Number,null],
				default:false
			},
			//组件为等比例固定，使用高度确定其尺寸
			height:{
				type:[String,null],
				default:""
			},
			radius:{
				type:[String,Number,null],
				default:null
			},
			size:{
				type:[String,null],
				default:null
			},
			borderWidth:{
				type:[String,Number,null],
				default:null
			},
			buttonIcon:{
				type:[String,null],
				default:""
			},
			buttonText:{
				type:[String,null],
				default:""
			},
			buttonClass:{
				type:[String,null],
				default:""
			},
			disabled:{
				type:[Boolean,null],
				default:false
			},//只读，只能系统更改
			readOnly:{
				type:[Boolean,null],
				default:false
			}
		},
		data() {
			return {
				inChecked:false,
			}
		},
		computed:{
			//将默认值内含到css、计算属性等地方，只内含真值
			//规避特殊使用的情况下，由prop传入undefined、null等无效数据导致的，默认值失效问题。例如组件嵌套且需要组件间参数传递
			//HBuilder X3.3.13; 微信开发者工具stable 1.05.2111300
			//微信小程序会对传入的undefined、null值根据参数类型输出不同空值(false、""、null、0)，参数类型为null或未指定参数类型则输出null
			//H5会对传入的undefined取默认值，未设默认值则输出undefined。对传入的null值固定输出null
			//做参数传递时需警惕两者行为不同而造成的陷阱，主要问题出现在微信小程序的空值转化，输出非用户传入的空值、假值，使默认真值丢失
			//兼容空值取默认值的可行方案目前为，参数类型加入null如[Boolean,null]，判断传入参数是否为定义的类型，是则使用，否则赋予默认值
			setting(){
				return {
					type: this.$api.isDefined(this.type)? this.type :"primary",
					size: this.$api.isDefined(this.size)? this.size :"md",
					onValue: this.$api.isDefined(this.onValue)? this.onValue :true,
					radius: this.$api.isDefined(this.radius)? this.radius :"circle",
					borderWidth: this.$api.isValue(this.borderWidth)? this.borderWidth :1,
				}
			},
			W(){
				if(this.height){
					let res = this.$api.splitUnit(this.height);
					return res[0]*5/3 + res[1]
				}
				return ""
			},
			borW(){
				let borderWidth = this.setting.borderWidth;
				if(borderWidth){
					if(this.$api.isNumber(borderWidth, true)){
						return borderWidth+"px"
					}
					return borderWidth
				}
				return 0
			},
			distance(){//偏移距离，使用自定义高度时有效
				if(this.inChecked){
					return "40%"
				}
				return '-' + this.borW
			}
		},
		methods:{
			emitEvent(value){//事件合并
				this.$emit("input", value);
				this.$emit("change", value);
			},
			onChange(){
				if(this.disabled || this.readOnly){
					return
				}
				this.inChecked = !this.inChecked;
				if(this.mode == "value"){
					if(this.inChecked){
						this.emitEvent(this.setting.onValue)
					}else{
						this.emitEvent(this.offValue)
					}
				}else{
					this.emitEvent(this.inChecked);
				}
			}
		},
		watch:{
			"checked":{
				immediate:true,
				handler(newVal){
					if(this.mode != "value"){
						this.inChecked = !!newVal
					}
				}
			},
			"value":{
				immediate:true,
				handler(newVal){
					if(this.mode == "value"){
						this.inChecked = this.setting.onValue === newVal;
					}
				}
			}
		}
	}
</script>

<style lang="scss">
$transition:.3s;
.vi_switch{
	display: inline-block;
	.vi_switch_box{
		position: relative;
		.vi_switch_block{
			position: absolute;
			transition: left $transition, border-color $transition, color $transition;
			display: flex;
			justify-content: center;
			align-items: center;
			line-height: 1;
			box-sizing: border-box;
		}
	}
}
.vi_switch .vi_shadow_sm /deep/ .vi_styleController{
	box-shadow: 0px 1px 2px #ddd;
}
.vi_switch .vi_shadow_md /deep/ .vi_styleController{
	box-shadow: 0 1px 3px #ddd;
}
.vi_switch .vi_shadow_lg /deep/ .vi_styleController{
	box-shadow: 0 1px 3px #ddd;
}
</style>
